package elec315.chatroom.core.processor;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import elec315.chatroom.client.ui.UIBuilder;
import elec315.chatroom.constant.ChatConstant;
import elec315.chatroom.msg.BaseMsg;
import elec315.chatroom.msg.MsgId;
import elec315.chatroom.msg.ReturnCode;
import elec315.chatroom.msg.authentication.ChatLoginNtyMsg;
import elec315.chatroom.msg.authentication.ChatLoginResMsg;
import elec315.chatroom.msg.authentication.ChatLogoutNtyMsg;
import elec315.chatroom.msg.authentication.ChatLogoutResMsg;
import elec315.chatroom.msg.chat.ChatBroadcastNtyMsg;
import elec315.chatroom.msg.user.ChatGetUserListResMsg;
import elec315.chatroom.net.ClientSocketHandler;
import elec315.chatroom.net.SocketHandler;

public class ClientMessageProcessor implements MessageProcessor {

	private static final Log logger = LogFactory.getLog(ClientMessageProcessor.class);

	private static final DateFormat dateFormatter = new SimpleDateFormat(ChatConstant.DATE_FORMAT);

	private final UIBuilder ui;

	public ClientMessageProcessor(UIBuilder ui) {
		super();
		this.ui = ui;
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see elec315.chatroom.core.processor.MessageProcessor#process(elec315.chatroom.msg.BaseMsg,
	 *      elec315.chatroom.net.SocketHandler)
	 */
	public void process(BaseMsg baseMsg, SocketHandler socketHandler) {
		ClientSocketHandler clientSocketHandler = (ClientSocketHandler) socketHandler;
		MsgId msgId = baseMsg.getMsgId();

		switch (msgId) {
		case CHAT_RES_LOGIN: {
			ChatLoginResMsg resMsg = (ChatLoginResMsg) baseMsg;
			processChatLoginResMsg(resMsg, clientSocketHandler);
			break;
		}
		case CHAT_NTY_LOGIN: {
			ChatLoginNtyMsg ntyMsg = (ChatLoginNtyMsg) baseMsg;
			processChatLoginNtyMsg(ntyMsg, clientSocketHandler);
			break;
		}
		case CHAT_RES_LOGOUT: {
			ChatLogoutResMsg resMsg = (ChatLogoutResMsg) baseMsg;
			processChatLogoutResMsg(resMsg, clientSocketHandler);
			break;
		}
		case CHAT_NTY_LOGOUT: {
			ChatLogoutNtyMsg ntyMsg = (ChatLogoutNtyMsg) baseMsg;
			processChatLogoutNtyMsg(ntyMsg, clientSocketHandler);
			break;
		}
		case CHAT_NTY_BROADCAST: {
			ChatBroadcastNtyMsg resMsg = (ChatBroadcastNtyMsg) baseMsg;
			processChatBroadcastNty(resMsg, clientSocketHandler);
			break;
		}
		case CHAT_RES_GET_USER_ID_LIST: {
			ChatGetUserListResMsg resMsg = (ChatGetUserListResMsg) baseMsg;
			processChatGetUserListResMsg(resMsg, clientSocketHandler);
			break;
		}
		default:
			logger.error("Unhandled msgId: " + msgId);
			break;
		}
	}

	private void processChatLoginResMsg(ChatLoginResMsg resMsg, ClientSocketHandler clientSocketHandler) {
		if (logger.isDebugEnabled()) {
			logger.debug("Received resMsg: " + resMsg);
		}
		Date msgTime = resMsg.getMsgTime();
		String userId = resMsg.getUserId();
		ReturnCode returnCode = resMsg.getReturnCode();
		if (returnCode == ReturnCode.SUCESS) {
			clientSocketHandler.setUserId(userId);
		} else {
			ui.printMessage(String.format("%s Login failed", getMessageTime(msgTime)));
		}
	}

	private void processChatLoginNtyMsg(ChatLoginNtyMsg ntyMsg, ClientSocketHandler clientSocketHandler) {
		if (logger.isDebugEnabled()) {
			logger.debug("Received ntyMsg: " + ntyMsg);
		}
		Date msgTime = ntyMsg.getMsgTime();
		String userId = ntyMsg.getUserId();
		ui.printMessage(String.format("%s <%s> just signed in.", getMessageTime(msgTime), userId));
	}

	private void processChatLogoutResMsg(ChatLogoutResMsg resMsg, ClientSocketHandler clientSocketHandler) {
		if (logger.isDebugEnabled()) {
			logger.debug("Received resMsg: " + resMsg);
		}
		Date msgTime = resMsg.getMsgTime();
		ReturnCode returnCode = resMsg.getReturnCode();
		if (returnCode != ReturnCode.SUCESS) {
			ui.printMessage(String.format("%s Logout failed", getMessageTime(msgTime)));
		}
	}

	private void processChatLogoutNtyMsg(ChatLogoutNtyMsg ntyMsg, ClientSocketHandler clientSocketHandler) {
		if (logger.isDebugEnabled()) {
			logger.debug("Received ntyMsg: " + ntyMsg);
		}
		Date msgTime = ntyMsg.getMsgTime();
		String userId = ntyMsg.getUserId();
		ui.printMessage(String.format("%s <%s> just left.", getMessageTime(msgTime), userId));
	}

	private void processChatBroadcastNty(ChatBroadcastNtyMsg ntyMsg, ClientSocketHandler clientSocketHandler) {
		if (logger.isDebugEnabled()) {
			logger.debug("Received ntyMsg: " + ntyMsg);
		}
		Date msgTime = ntyMsg.getMsgTime();
		String userId = ntyMsg.getUserId();
		String message = ntyMsg.getMessage();
		ui.printMessage(String.format("%s %s: %s", getMessageTime(msgTime), userId, message));
	}

	private void processChatGetUserListResMsg(ChatGetUserListResMsg resMsg, ClientSocketHandler clientSocketHandler) {
		if (logger.isDebugEnabled()) {
			logger.debug("Received resMsg: " + resMsg);
		}
		ReturnCode returnCode = resMsg.getReturnCode();
		if (returnCode == ReturnCode.SUCESS) {
			List<String> userIds = resMsg.getUserIds();
			Collections.sort(userIds);
			if (!userIds.isEmpty()) {
				String str = "User list:";
				for (int i = 0; i < userIds.size(); i++) {
					str += "\n" + (i + 1) + ". " + userIds.get(i);
				}
				ui.printMessage(str);
			}
		} else {
			ui.printMessage("Failed to get user list.");
		}
	}

	private String getMessageTime(Date msgTime) {
		return String.format("[%s]", dateFormatter.format(msgTime));
	}
}
